#ifndef FLEXICACHE_PRELOADER
#define FLEXICACHE_PRELOADER

#include <time.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <libxml/parser.h>
#include <libxml/xmlmemory.h>
#include "llist.h"

#define BUF_SIZE_16   16
#define BUF_SIZE_64   64
#define BUF_SIZE_128  128
#define BUF_SIZE_256  256
#define BUF_SIZE_512  512
#define BUF_SIZE_1024 1024
#define BUF_SIZE_2048 2048
#define BUF_SIZE_4096 4096
#define EPOLL_TIMEOUT 100
#define PRELOADER_TIMEOUT 60
#define PRELOADER_FD_MAX 65535
#define PRELOADER_MAX_EVENTS 10240
#define LOCAL_DEFAULT_IP "0.0.0.0"
#define LOCAL_DEFAULT_PORT 20127
#define LOG_ROTATE_NUMBER 5
#define LOG_ROTATE_SIZE 10240000
#define PRELOADER_LOG_DIR "/var/log/chinacache"
#define PRELOADER_LOG_FILE "/var/log/chinacache/preloader.log"
#define PRELOADER_PID_FILE "/var/run/preloader/preloader.pid"
#define PRELOADER_PID_DIR  "/var/run/preloader"

#define plog(logtype, fmt, args...) preloaderlog(logtype, __FILE__, __LINE__, fmt, ##args)

enum LOG_TYPE {
	COMMON = 0,
	WARNING,
	ERROR,
	FATAL
};

enum object {
	OBJ_ADD,                 //add object into link list
	OBJ_MOD,                 //modify object in link list
	OBJ_DEL,                 //delete object from link list
	OBJ_INIT,                //create link list
	OBJ_FIND,                //find object in link list
	OBJ_TRAVEL,              //travel link list
	OBJ_NUMBER,              //get link list node number
	OBJ_ISEMPTY              //check link list is empty or not
};

enum epoll { 
	EPOLL_INIT,              //epoll initialize
	EPOLL_ADD,               //epoll add
	EPOLL_MOD,               //epoll modify
	EPOLL_DEL,               //epoll delete
	EPOLL_WAIT,              //epoll wait
	EPOLL_IN,                //socket fd can read
	EPOLL_OUT,               //socket fd can write
	EPOLL_HUP,               //epoll hang up
	EPOLL_ERR,               //epoll error
	EPOLL_FLD,               //epoll failed
	EPOLL_SUCC,              //epoll success
	EPOLL_DESTROY            //epoll destroy
};

enum FLAGS {
	TRUE = -100,
	FALSE,
	SUCC,
	FAILED,
	ADDR,
	DATA,
	USE,
	RELEASE
};

enum ACTION {
	ACTION_UNKNOWN,
	ACTION_URL_PURGE,
	ACTION_URL_EXPIRE,
	ACTION_URL_PRELOAD,
	ACTION_DIR_PURGE,
	ACTION_DIR_EXPIRE,
	ACTION_DIR_PRELOAD,
	ACTION_URL,
	ACTION_DIR,
};

typedef struct socket_data_st {
	int sockfd;
	int direction;
	char *buffer;
	size_t send_data_length;
	size_t recv_data_length;
} socket_data_t;

typedef struct peerk_data_st {
	size_t hdrlen; 
	size_t contlen;
} peek_data_t;

typedef struct url_node_st {
	int id;
	int status;
	char *url;
	char code[4];
	char md5[BUF_SIZE_64];
	struct url_node_st *next;
} url_node_t;

typedef struct url_list_st {
	int number;
	url_node_t *head;
	url_node_t *tail;
	url_node_t *list;
} url_list_t;

typedef struct task_st {
	int action;
	int method;
	int sockfd;
	size_t buflen;
	size_t recvlen;
	char *buf;
	char *buffer;
	char *sessionid;
	char ip[BUF_SIZE_16];
	char report_address[BUF_SIZE_16];
	url_list_t urls;
} task_t;

typedef struct preloader_typesize_st {
	int task_t_size;
	int peek_data_t_size;
	int sock_index_t_size;
	int detect_obj_t_size;
} typesize_t;

typedef struct sock_index_st {
	int inuse;
	time_t timestamp;
	task_t *rfc;
} sock_index_t;

typedef struct preloader_index_st {
	int num;
	int max_sockfd;
	sock_index_t *idx; 
} preloader_index_t;

typedef struct preloader_st {
	int port;
	FILE *logfp; 
	int listenfd;
	LLIST *tasklist;
	preloader_index_t index;
} preloader_t; 

typedef struct detect_obj_st {
	int type;                                 //THRD_SAFE, THRD_NSAFE, HEAD, TAIL, MINHEAD or MAXHEAD
	int size;                                 //object size
	int number;                               //object number
	void *obj;                                //insert data
	void *entry;                              //temporary variable
	void *cmp;                                //compare rule
	void *travel;                             //travel method
	LLIST *llist;                             //link list
} detect_obj_t;

typedef int EWCB(const int type, const int sockfd); 

extern struct preloader_st preloader;

int openLogFile(void);
void closeLogFile(void);
void preloaderlog(const int logtype, const char *filename, const int nline, char *format, ...);
int detectObjCall(const int type, void *obj);
int detectEpollCall(const int calltype, const int sockfd, const int event, EWCB *callback);

#endif
